package net.jgrm.redisadvanced.service.impl;

import lombok.extern.slf4j.Slf4j;
import net.jgrm.redisadvanced.config.RedisAdvancedProperties;
import net.jgrm.redisadvanced.service.RedisHyperLogLogService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * Redis HyperLogLog类型操作服务实现类
 */
@Slf4j
@Service
public class RedisHyperLogLogServiceImpl implements RedisHyperLogLogService {

    private final RedisTemplate<String, Object> redisTemplate;
    private final RedisAdvancedProperties redisAdvancedProperties;

    public RedisHyperLogLogServiceImpl(RedisTemplate<String, Object> redisTemplate, RedisAdvancedProperties redisAdvancedProperties) {
        this.redisTemplate = redisTemplate;
        this.redisAdvancedProperties = redisAdvancedProperties;
    }

    /**
     * 添加前缀到键名
     */
    private String addPrefix(String key) {
        return redisAdvancedProperties.getKeyPrefix() + key;
    }

    @Override
    public Long add(String key, Object... values) {
        try {
            Long result = redisTemplate.opsForHyperLogLog().add(addPrefix(key), values);
            log.debug("HyperLogLog add successful: key={}", key);
            return result;
        } catch (Exception e) {
            log.error("HyperLogLog add error: key={}, error={}", key, e.getMessage(), e);
            throw new RuntimeException("Redis hyperloglog add operation failed", e);
        }
    }

    @Override
    public Long size(String... keys) {
        try {
            // 添加前缀到所有键名
            String[] keysWithPrefix = new String[keys.length];
            for (int i = 0; i < keys.length; i++) {
                keysWithPrefix[i] = addPrefix(keys[i]);
            }

            Long result = redisTemplate.opsForHyperLogLog().size(keysWithPrefix);
            log.debug("HyperLogLog size successful: keys={}", (Object) keys);
            return result;
        } catch (Exception e) {
            log.error("HyperLogLog size error: keys={}, error={}", (Object) keys, e.getMessage(), e);
            throw new RuntimeException("Redis hyperloglog size operation failed", e);
        }
    }

    @Override
    public Long merge(String destination, String... sourceKeys) {
        try {
            // 添加前缀到目标键和源键
            String destinationWithPrefix = addPrefix(destination);
            String[] sourceKeysWithPrefix = new String[sourceKeys.length];
            for (int i = 0; i < sourceKeys.length; i++) {
                sourceKeysWithPrefix[i] = addPrefix(sourceKeys[i]);
            }

            Long result = redisTemplate.opsForHyperLogLog().union(destinationWithPrefix, sourceKeysWithPrefix);
            log.debug("HyperLogLog merge successful: destination={}, sourceKeys={}", destination, (Object) sourceKeys);
            return result;
        } catch (Exception e) {
            log.error("HyperLogLog merge error: destination={}, sourceKeys={}, error={}",
                    destination, (Object) sourceKeys, e.getMessage(), e);
            throw new RuntimeException("Redis hyperloglog merge operation failed", e);
        }
    }

    @Override
    public Boolean delete(String key) {
        try {
            Boolean result = redisTemplate.delete(addPrefix(key));
            log.debug("HyperLogLog delete successful: key={}", key);
            return result;
        } catch (Exception e) {
            log.error("HyperLogLog delete error: key={}, error={}", key, e.getMessage(), e);
            throw new RuntimeException("Redis hyperloglog delete operation failed", e);
        }
    }

    @Override
    public Boolean expire(String key, long expireTime, TimeUnit timeUnit) {
        try {
            Boolean result = redisTemplate.expire(addPrefix(key), expireTime, timeUnit);
            log.debug("HyperLogLog expire successful: key={}, expireTime={}, timeUnit={}", key, expireTime, timeUnit);
            return result;
        } catch (Exception e) {
            log.error("HyperLogLog expire error: key={}, error={}", key, e.getMessage(), e);
            throw new RuntimeException("Redis hyperloglog expire operation failed", e);
        }
    }
}